# -*- coding: utf-8 -*-
import datetime
import logging
from decimal import Decimal

from base.connection import get_db_session
from conf.config import FACTORY_ID
import time
import random

logger = logging.getLogger("payment")


def generator_trade_no():
    """
    生成订单号
    :return:
    """
    t = int(1000 * time.time())
    r = random.randint(1000, 9999)
    return ''.join(map(lambda i: str(i), (t, r)))


def update_account_money(user_id, money, cashable=False, remarks=""):
    """
    更新账户金额
    :param user_id: 用户帐号字符串
    :param money: 负数表示付款，正数表示充值
    :param cashable: 是否可提现
    :param remarks: 备注
    :return: 是否成功
    """

    class AccountMoney(object):
        pass

    session = get_db_session([
        {"db_table": "ebt_account_money", "model": AccountMoney},
    ])
    am = session.query(AccountMoney).filter_by(ebf_am_user_id=user_id).first()
    if not am:
        # 没有账户时创建账户
        am = AccountMoney()
        am.ebf_am_user_id = user_id
        am.ebf_am_account_type = 2
        am.ebf_am_money = 0
        am.ebf_am_cash = 0
        am.ebf_am_is_forbid = 0
        am.ebf_am_create_date = datetime.datetime.utcnow()
        am.ebf_am_remarks = remarks
        session.add(am)
        session.commit()

    # 这里账户余额被禁用的话也可以加钱，但是不可以付钱
    if money <= 0 and am.ebf_am_is_forbid == 1:
        session.close()
        return False

    am_money = am.ebf_am_money
    am_money = am_money + Decimal(money)
    am_cash = am.ebf_am_cash
    if cashable:
        am_cash = am_cash + Decimal(money)
    logger.info(f"[帐号={user_id}]操作前余额={am.ebf_am_money},操作后余额={am_money}")
    # 需要保证付款后账户余额不为负数
    if am_money >= 0:
        am.ebf_am_money = am_money
        # 需要保证可提现余额不超过余额总额
        if am_money < am.ebf_am_cash:
            am.ebf_am_cash = am_money
        session.commit()
        session.close()
        return True
    session.close()
    return False


def update_account_cash(user_id, money, remarks=""):
    """
    更新账户可提现金额
    :param user_id: 用户帐号字符串
    :param money: 负数表示付款，正数表示充值
    :param remarks: 备注
    :return: 是否成功
    """

    class AccountMoney(object):
        pass

    session = get_db_session([
        {"db_table": "ebt_account_money", "model": AccountMoney},
    ])
    am = session.query(AccountMoney).filter_by(ebf_am_user_id=user_id).first()
    if not am:
        # 没有账户时创建账户
        am = AccountMoney()
        am.ebf_am_user_id = user_id
        am.ebf_am_account_type = 2
        am.ebf_am_money = 0
        am.ebf_am_cash = 0
        am.ebf_am_is_forbid = 0
        am.ebf_am_create_date = datetime.datetime.utcnow()
        am.ebf_am_remarks = remarks
        session.add(am)
        session.commit()

    # 这里账户余额被禁用的话也可以加钱，但是不可以付钱
    if money <= 0 and am.ebf_am_is_forbid == 1:
        session.close()
        return False

    am_money = am.ebf_am_money
    am_money = am_money + Decimal(money)
    am_cash = am.ebf_am_cash
    am_cash = am_cash + Decimal(money)
    logger.info(f"[帐号={user_id}]操作前余额={am.ebf_am_money},操作后余额={am_money}, 操作前可提现={am.ebf_am_cash}, 操作后可提现={am_cash}")

    # 需要保证付款后账户余额和可提现不为负数
    if am_money >= 0 and am_cash >= 0:
        am.ebf_am_money = am_money
        am.ebf_am_cash = am_cash
        # 需要保证可提现余额不超过余额总额
        if am_money < am.ebf_am_cash:
            am.ebf_am_cash = am_money
        session.commit()
        session.close()
        return True
    session.close()
    return False


def create_balance_record(user_id, money, trade_no):
    """
    购买时用余额支付或者余额微信混合支付时创建余额消费记录
    :param user_id:
    :param money:
    :param trade_no:
    :return:
    """
    class User(object):
        pass

    class Pay(object):
        pass

    class Agency(object):
        pass

    session = get_db_session([
        {"db_table": "ebt_user", "model": User},
        {"db_table": "ebt_pay", "model": Pay},
        {"db_table": "ebt_agency", "model": Agency},
    ])

    try:
        now = datetime.datetime.utcnow()
        pay = Pay()
        pay.ebf_device_id = None
        pay.ebf_user_id = user_id
        pay.ebf_pay_trade_no = trade_no
        pay.ebf_pay_fee = money
        pay.ebf_pay_is_success = 1
        pay.ebf_pay_create_date = now
        pay.ebf_pay_type = 4
        pay.ebf_pay_trade_type = 1
        pay.ebf_pay_account = "余额消费"
        pay.ebf_pay_remarks = "余额消费"
        pay.ebf_pay_status = 1
        pay.ebf_pay_pay_date = now

        try:
            user = session.query(User).filter_by(ebf_user_id=user_id).first()
            agency = session.query(Agency).filter_by(ebf_agency_uid=user.ebf_user_agency_uid).first()
            pay.ebf_pay_agency_id = agency.ebf_agency_id
        except Exception as e:
            logger.exception(e)
            pay.ebf_pay_agency_id = None

        pay.ebf_pay_factory_id = FACTORY_ID
        pay.ebf_pay_remote_ip = ""
        session.add(pay)
        session.commit()
    except Exception as e:
        logger.exception(e)
        return False

    return True


class BalanceHandler(object):
    def __init__(self):
        pass

    @staticmethod
    def add_manual_money(user_id, money, operator="", ip="", pay_content="系统退款自动充值"):
        """
        手工添加账单（思达尔专用）
        :return:
        """
        try:
            # 更新账户金额
            is_success = update_account_money(user_id, money)
            if not is_success:
                raise Exception("充值异常")

            class User(object):
                pass

            class Pay(object):
                pass

            class Agency(object):
                pass

            class ChargeRecord(object):
                pass

            session = get_db_session([
                {"db_table": "ebt_user", "model": User},
                {"db_table": "ebt_pay", "model": Pay},
                {"db_table": "ebt_agency", "model": Agency},
                {"db_table": "ebt_charge_record", "model": ChargeRecord},
            ])
            trade_no = generator_trade_no()
            # 添加充值记录
            charge_record = ChargeRecord()
            charge_record.ebf_cr_user_id = user_id
            charge_record.ebf_cr_type = 1
            charge_record.ebf_cr_trade_no = trade_no
            charge_record.ebf_cr_pay_account = ""
            charge_record.ebf_cr_status = 1
            charge_record.ebf_cr_pay_money = money
            charge_record.ebf_cr_rate = 1
            charge_record.ebf_cr_account_money = money
            charge_record.ebf_cr_update_date = datetime.datetime.utcnow()
            charge_record.ebf_cr_create_date = datetime.datetime.utcnow()
            session.add(charge_record)

            # 创建订单
            now = datetime.datetime.utcnow()
            pay = Pay()
            pay.ebf_device_id = None
            pay.ebf_user_id = user_id
            pay.ebf_pay_trade_no = trade_no
            pay.ebf_pay_fee = money
            pay.ebf_pay_is_success = 1
            pay.ebf_pay_create_date = now
            pay.ebf_pay_type = 5
            pay.ebf_pay_trade_type = 2
            pay.ebf_pay_account = pay_content
            pay.ebf_pay_remarks = f"充值人员：{operator}"
            pay.ebf_pay_status = 1
            pay.ebf_pay_pay_date = now

            try:
                user = session.query(User).filter_by(ebf_user_id=user_id).first()
                agency = session.query(Agency).filter_by(ebf_agency_uid=user.ebf_user_agency_uid).first()
                pay.ebf_pay_agency_id = agency.ebf_agency_id
            except Exception as e:
                logger.exception(e)
                pay.ebf_pay_agency_id = None

            pay.ebf_pay_factory_id = FACTORY_ID
            pay.ebf_pay_remote_ip = ip
            session.add(pay)
            session.commit()
            session.close()
        except Exception as e:
            logger.exception(e)
            return False
        logger.info(
            f"充值成功: trade_no={trade_no} openid={user_id} money={money} operator={operator} ip={ip} remarks={pay_content}")
        return True

    @staticmethod
    def add_account_cash(user_id, money, trade_no, operator="", ip="", pay_content="系统自动充值"):
        """
        添加可提现余额账单（思达尔专用）
        :return:
        """
        try:

            class User(object):
                pass

            class Pay(object):
                pass

            class Agency(object):
                pass

            class ChargeRecord(object):
                pass

            session = get_db_session([
                {"db_table": "ebt_user", "model": User},
                {"db_table": "ebt_pay", "model": Pay},
                {"db_table": "ebt_agency", "model": Agency},
                {"db_table": "ebt_charge_record", "model": ChargeRecord},
            ])

            # 幂等处理，防止重复充值
            cr = session.query(ChargeRecord).filter_by(ebf_cr_trade_no=trade_no).first()
            if cr:
                logger.error(f"充值失败: 已经有充值记录 open_id={user_id} trade_no={trade_no}")
                return False

            # 更新账户金额
            is_success = update_account_cash(user_id, money)
            if not is_success:
                raise Exception("可提现余额充值异常")

            # 添加充值记录
            charge_record = ChargeRecord()
            charge_record.ebf_cr_user_id = user_id
            charge_record.ebf_cr_type = 1
            charge_record.ebf_cr_trade_no = trade_no
            charge_record.ebf_cr_pay_account = ""
            charge_record.ebf_cr_status = 1
            charge_record.ebf_cr_pay_money = money
            charge_record.ebf_cr_rate = 1
            charge_record.ebf_cr_account_money = money
            charge_record.ebf_cr_update_date = datetime.datetime.utcnow()
            charge_record.ebf_cr_create_date = datetime.datetime.utcnow()
            session.add(charge_record)

            # 创建订单
            now = datetime.datetime.utcnow()
            pay = Pay()
            pay.ebf_device_id = None
            pay.ebf_user_id = user_id
            pay.ebf_pay_trade_no = trade_no
            pay.ebf_pay_fee = money
            pay.ebf_pay_is_success = 1
            pay.ebf_pay_create_date = now
            pay.ebf_pay_type = 5
            pay.ebf_pay_trade_type = 2
            pay.ebf_pay_account = pay_content
            pay.ebf_pay_remarks = f"可提现充值: 充值人员: {operator}"
            pay.ebf_pay_status = 1
            pay.ebf_pay_pay_date = now

            try:
                user = session.query(User).filter_by(ebf_user_id=user_id).first()
                agency = session.query(Agency).filter_by(ebf_agency_uid=user.ebf_user_agency_uid).first()
                pay.ebf_pay_agency_id = agency.ebf_agency_id
            except Exception as e:
                logger.exception(e)
                pay.ebf_pay_agency_id = None

            pay.ebf_pay_factory_id = FACTORY_ID
            pay.ebf_pay_remote_ip = ip
            session.add(pay)
            session.commit()
            session.close()
        except Exception as e:
            logger.exception(e)
            return False
        logger.info(
            f"充值成功: trade_no={trade_no} openid={user_id} money={money} operator={operator} ip={ip} remarks={pay_content}")
        return True

    @staticmethod
    def reduce_money(user_id, trade_no, money, price_total_rate, ip):
        """
        扣款（思达尔专用）
        :return:
        """
        try:

            # 更新账户金额
            is_success = update_account_money(user_id, -money)
            if not is_success:
                raise Exception("扣款异常")
                # todo 去掉余额提成的计算，可以不计算或者放到订单完成时再计算
                # class User(object):
                #     pass
                #
                # class Pay(object):
                #     pass
                #
                # class Agency(object):
                #     pass
                #
                # session = get_db_session([
                #     {"db_table": "ebt_user", "model": User},
                #     {"db_table": "ebt_pay", "model": Pay},
                #     {"db_table": "ebt_agency", "model": Agency},
                # ])
                # # 创建订单
                # now = datetime.datetime.utcnow()
                # pay = Pay()
                # pay.ebf_device_id = None
                # pay.ebf_user_id = user_id
                # pay.ebf_pay_trade_no = trade_no
                # pay.ebf_pay_fee = price_total_rate
                # pay.ebf_pay_is_success = 1
                # pay.ebf_pay_create_date = now
                # pay.ebf_pay_type = 4
                # pay.ebf_pay_trade_type = 1
                # pay.ebf_pay_content = "余额消费"
                # pay.ebf_pay_remarks = "余额消费"
                # pay.ebf_pay_status = 1
                # pay.ebf_pay_pay_date = now
                #
                # user = session.query(User).filter_by(ebf_user_id=user_id).first()
                # agency = session.query(Agency).filter_by(ebf_agency_uid=user.ebf_user_agency_uid).first()
                # if agency:
                #     pay.ebf_pay_agency_id = agency.ebf_agency_id
                # else:
                #     pay.ebf_pay_agency_id = None
                #
                # pay.ebf_pay_factory_id = user.ebf_user_factory_id
                # pay.ebf_pay_account = ""
                # pay.ebf_pay_remote_ip = ip
                # session.add(pay)
                # session.flush()
                # session.commit()
                # session.close()
        except Exception as e:
            logger.exception(e)
            return False

        return True

    @staticmethod
    def get_balance(user_id):
        """
        获取用户余额

        :param user_id: 用户帐号字符串
        :return: balance: 用户余额
        """
        class AccountMoney(object):
            pass

        session = get_db_session([
            {"db_table": "ebt_account_money", "model": AccountMoney},
        ])

        am = session.query(AccountMoney).filter_by(ebf_am_user_id=user_id).first()
        if not am:
            # 没有账户时创建账户
            am = AccountMoney()
            am.ebf_am_user_id = user_id
            am.ebf_am_account_type = 2
            am.ebf_am_money = 0
            am.ebf_am_cash = 0
            am.ebf_am_is_forbid = 0
            am.ebf_am_create_date = datetime.datetime.utcnow()
            am.ebf_am_remarks = "get_balance"
            session.add(am)
            session.commit()

        am_money = am.ebf_am_money
        session.close()
        return am_money

    @staticmethod
    def change_balance_cashable(user_id, money, remarks=""):
        """
        账户余额转为可提现金额
        :param user_id: 用户帐号字符串
        :param money: 负数表示付款，正数表示充值
        :param remarks: 备注
        :return: 已转可提现金额
        """

        class AccountMoney(object):
            pass

        session = get_db_session([
            {"db_table": "ebt_account_money", "model": AccountMoney},
        ])

        am = session.query(AccountMoney).filter_by(ebf_am_user_id=user_id).first()
        if not am:
            # 没有账户时创建账户
            am = AccountMoney()
            am.ebf_am_user_id = user_id
            am.ebf_am_account_type = 2
            am.ebf_am_money = 0
            am.ebf_am_cash = 0
            am.ebf_am_is_forbid = 0
            am.ebf_am_create_date = datetime.datetime.utcnow()
            am.ebf_am_remarks = remarks
            session.add(am)
            session.commit()

        money = Decimal(money)
        if money <= Decimal(0):
            session.close()
            logger.error(f"余额转可提现：NG 要转金额小于0")
            return Decimal(0)

        am_money = am.ebf_am_money
        am_cash = am.ebf_am_cash
        if am_money - am_cash >= money:
            am_cash += money
            cashed = money
        else:
            cashed = am_money - am_cash
            am_cash = am_money
        logger.info(f"余额转可提现：[帐号={user_id}] 操作前余额={am.ebf_am_money}, 操作后余额={am_money}, 操作前可提现={am.ebf_am_cash}, 操作后可提现={am_cash} money={money} remarks: {remarks}")

        # 需要保证付款后账户余额和可提现不为负数
        if am_money >= 0 and am_cash >= 0:
            am.ebf_am_money = am_money
            am.ebf_am_cash = am_cash
            # 需要保证可提现余额不超过余额总额
            if am_money < am.ebf_am_cash:
                am.ebf_am_cash = am_money
            session.commit()
            session.close()
            return cashed
        session.commit()
        session.close()
        logger.error(f"余额转可提现：NG 账户金额小于0 open_id={user_id} money={money} remarks={remarks}")
        return Decimal(0)

    @staticmethod
    def get_balance_charge_records(user_id, order_id):
        """
        按单号获取用户余额充值记录

        :param user_id: 用户帐号字符串
        :param order_id: 订单号码
        :return: charge_record: 用户余额记录
        """
        class ChargeRecord(object):
            pass

        session = get_db_session([
            {"db_table": "ebt_charge_record", "model": ChargeRecord},
        ])

        return session.query(ChargeRecord).filter_by(ebf_cr_trade_no=order_id, ebf_cr_user_id=user_id).first()
